/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "drivers/i2c.h"
#include <iostream>
#include <map>
#include <mutex>
#include <thread>
#include <chrono>

namespace DRIVER_I2C {

// 全局存储映射，模拟硬件内存
// 使用复合键 (addr, offset) 来存储数据
struct MemoryKey {
    uint32_t addr;
    uint32_t offset;

    bool operator<(const MemoryKey& other) const {
        if (addr != other.addr) {
            return addr < other.addr;
        }
        return offset < other.offset;
    }
};

static std::map<MemoryKey, std::string> g_memory_map;
static std::mutex                       g_memory_mutex;

// 总线互斥锁 - 每个I2C实例都有自己的锁
static std::map<uint8_t, std::unique_ptr<std::mutex>> g_bus_locks;
static std::mutex                                      g_bus_locks_mutex;

void I2c::init(uint8_t id, uint32_t speed, uint8_t mode, uint8_t slave_addr) {
    // 打桩实现：记录初始化参数
    std::cout << "I2C驱动初始化: ID=" << static_cast<int>(id) << ", Speed=" << speed
              << ", Mode=" << static_cast<int>(mode)
              << ", SlaveAddr=" << static_cast<int>(slave_addr) << std::endl;
    
    // 设置默认的偏移量宽度为1
    m_offset_width = 1;
    m_bus_id = id;
    
    // 为每个总线创建独立的互斥锁
    {
        std::lock_guard<std::mutex> lock(g_bus_locks_mutex);
        if (g_bus_locks.find(id) == g_bus_locks.end()) {
            g_bus_locks[id] = std::make_unique<std::mutex>();
        }
    }
}

void I2c::lock() {
    // 真实的总线锁定实现
    std::mutex* bus_mutex = nullptr;
    {
        std::lock_guard<std::mutex> lock(g_bus_locks_mutex);
        auto it = g_bus_locks.find(m_bus_id);
        if (it != g_bus_locks.end()) {
            bus_mutex = it->second.get();
        }
    }
    
    if (bus_mutex) {
        bus_mutex->lock();
    }
}

void I2c::unlock() {
    // 真实的总线解锁实现
    std::mutex* bus_mutex = nullptr;
    {
        std::lock_guard<std::mutex> lock(g_bus_locks_mutex);
        auto it = g_bus_locks.find(m_bus_id);
        if (it != g_bus_locks.end()) {
            bus_mutex = it->second.get();
        }
    }
    
    if (bus_mutex) {
        bus_mutex->unlock();
    }
}

std::tuple<int, std::optional<std::string>> I2c::read(const I2C_READ_S* read_data,
                                                      std::string_view  tx_buf) {
    std::lock_guard<std::mutex> lock(g_memory_mutex);

    // 从 tx_buf 中解析地址和偏移量
    if (tx_buf.empty()) {
        std::cout << "I2C读取失败: 无效的地址" << std::endl;
        return std::make_tuple(-1, std::optional<std::string>());
    }

    uint32_t addr   = static_cast<uint8_t>(tx_buf[0]);
    uint32_t offset = 0;

    // 使用成员变量m_offset_width来解析偏移量
    size_t offset_bytes = std::min(static_cast<size_t>(m_offset_width), tx_buf.length() - 1);
    for (size_t i = 1; i <= offset_bytes; ++i) {
        offset |= (static_cast<uint8_t>(tx_buf[i]) << ((offset_bytes - i) * 8));
    }

    // 构建内存键
    MemoryKey key{addr, offset};

    // 从内存映射中读取数据
    auto it = g_memory_map.find(key);
    if (it != g_memory_map.end()) {
        std::string data = it->second;
        // 如果读取长度小于存储的数据长度，截取指定长度
        if (data.length() > read_data->length) {
            data = data.substr(0, read_data->length);
        }
        // 如果读取长度大于存储的数据长度，用默认值填充
        else if (data.length() < read_data->length) {
            data.append(read_data->length - data.length(), '\0');
        }
        
        return std::make_tuple(0, std::optional<std::string>(data));
    } else {
        // 如果地址不存在，返回默认数据
        std::string default_data(read_data->length, '\0');
        std::cout << std::endl;
        return std::make_tuple(0, std::optional<std::string>(default_data));
    }
}

int I2c::write(uint8_t id, std::string_view tx_buf, uint32_t timeout_ms, uint32_t flags) {
    std::lock_guard<std::mutex> lock(g_memory_mutex);

    // 从 tx_buf 中解析地址、偏移量和数据
    if (tx_buf.length() < 1) {
        std::cout << "I2C写入失败: 无效的数据" << std::endl;
        return -1;
    }

    uint32_t    addr   = static_cast<uint8_t>(tx_buf[0]);
    uint32_t    offset = 0;
    std::string data;

    // 使用成员变量m_offset_width来解析偏移量
    size_t offset_bytes = std::min(static_cast<size_t>(m_offset_width), tx_buf.length() - 1);
    for (size_t i = 1; i <= offset_bytes; ++i) {
        offset |= (static_cast<uint8_t>(tx_buf[i]) << ((offset_bytes - i) * 8));
    }

    // 剩余的数据（从偏移量之后开始）
    if (tx_buf.length() > offset_bytes + 1) {
        data = std::string(tx_buf.substr(offset_bytes + 1));
    }

    // 构建内存键
    MemoryKey key{addr, offset};

    // 将数据存储到内存映射中
    g_memory_map[key] = data;

    // 返回成功
    return 0;
}

} // namespace DRIVER_I2C